home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Networking / OTPAPSampleServer / PAPServerSample.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  58.0 KB  |  2,137 lines  |  [TEXT/CWIE]

  1. /*
  2.  
  3.     file: PAPServerSample.c
  4.     
  5.     This sample demonstrates the implementation of a PAP server using Open Transport.
  6.     
  7.     Issues:
  8.     1. PostScript Query responses are default only
  9.     To respond to the LaserWriter client, the PostScript query handler code is 
  10.     designed to return the default responses.  A real PAP spooler would have to
  11.     respond more appropriately for the printer that it is supporting.  This could mean
  12.     delaying the response back to the client until the spooler can actually
  13.     pass the query to the printer and get a real response.  The code for detecting
  14.     a PostScript query is not very robust.  The purpose of this sample was not to
  15.     demonstrate PostScript support, but to packet flow via OT.
  16.     
  17.     2. If the received data is not part of a PostScript query, the spooler sample
  18.     assumes that all of the incoming data is part of the same job.  There is no check
  19.     for the PostScript EOF indicator to distinguish different spooler jobs.  All of the 
  20.     incoming data is saved to a temporary disk file at the root of the boot hard drive.
  21.     The code does not try to preflight the amount of storage present, nor protect  
  22.     some minimum hard drive storage in case the hard drive is close to full.
  23.     
  24.     3.    This sample requires OT 1.1.2 or greater.
  25.     
  26.     4. This sample support multiple handoff endpoints.  The constant kMaxHandoffEPs
  27.     defines the maximum number of handoff endpoints that this sample supports.  I have
  28.     tested that the server supports 2 endpoint connections at the same time, but have not
  29.     gone into testing more simultaneous connections.      
  30.     
  31.     Change history
  32.     RRK 5/28/99 modified code to look for eof and respond to client with an empty packet with
  33.         the eof bit set.
  34.     
  35.     RRK 3/9/99 add new code to protect against multiple unbind calls on an endpoint
  36.     *    Renamed DoDisconnect to DoRcvDisconnect and implemented
  37.     *    Implemented DoSndDisconnect
  38.     *    Check for errors in hanlder
  39.     *    implemented OTLookHandler function
  40.     *    implemented the ActivateHandoffEndpoint function where the handoff endpoint is initialized, and bound
  41.     *    fixed bug to OTRcvDisconnect where we were passing unit'd &discon parameters.
  42.     *    set flags before making OT calls instead of after the call success to fix timing issues.
  43.     
  44.     by:        Rich Kubota
  45.             Developer Technical Support
  46.             
  47. */
  48.  
  49. #define  qDebug                1
  50. #define  HANDOFF_EP            1    // set to to to indicate use of handoff endpoint
  51.  
  52. #include <Types.h>
  53. #include <Errors.h>
  54. #include <String.h>
  55. #include <ToolUtils.h>
  56. #include "StringUtils.h"
  57. #include <AppleTalk.h>
  58. #include <DiskInit.h>
  59. #include <TextUtils.h>
  60. #include <Gestalt.h>
  61. #include <Files.h>
  62. #include <NumberFormatting.h>
  63. #include "OpenTransport.h"
  64. #include "OpenTptAppleTalk.h"
  65. #include "ATalkSampleUtils.h"
  66. #include "PAPServerUtilities.h"
  67. #include "PAPServerSample.h"
  68. #include "PAPPostScriptStuff.h"
  69. #include "OTDebug.h"
  70. #include "StrOpts.h"
  71.  
  72. extern  OSStatus OTSetMemoryLimits(size_t growSize, size_t maxSize);
  73.  
  74. /********************/
  75. /*     globals            */
  76. /********************/
  77. DDPAddress        gAddr;
  78. MyEndpointRef    gEp;
  79.  
  80. #if HANDOFF_EP
  81. MyEndpointRef    gHandoffEp[kMaxHandoffEPs];
  82. #endif
  83.  
  84. OTLIFO*            gFreeQ;            // note that an OTLIFO structure must be on a 4-byte boundary
  85.                                 // instead of trying to force it to be on a 4-byte boundary in
  86.                                 // global memory, we use a pointer, then allocate memory
  87.                                 // which will force the global to be on a 4-byte boundary.
  88. UInt32            gFlags    = 0;
  89. UInt32            gBufsAvail;
  90. PacketPtr        gTempPackPtr;
  91. short            gFRefNumToClose = 0;
  92. Boolean            gDone    = false;
  93. Str255            gIdleStr;
  94. Str255            gBusyStr;
  95. Str255            gServerNBPNameStr;
  96. UInt32            gOptionCompleted; // used to flag completion of Option Management calls
  97. extern char        gEOFStr[8];
  98. extern char        gBeginPSStr[8];
  99. extern char        qBeginQueryStr[8];
  100. extern char        gEndStr[8];
  101. extern char        gQueryStr[8];
  102.  
  103. OSType            gOTVersionSelector    = 'otvr';
  104. UInt32            gOTVersion;
  105.  
  106.  
  107. /*******************************************************************************
  108. ** Prototypes
  109. ********************************************************************************/
  110.  
  111. pascal    void    EventHandler(void*, OTEventCode, OTResult, void*);
  112. OSStatus        HandleOTLookErr(MyEndpointRef *myEp);
  113. static void     EnterListenAccept(MyEndpointRef *myServerEp);
  114. void            DoListenAccept(MyEndpointRef *myServerEp);
  115. Boolean         ReceiveOnePacket(MyEndpointRef *myEp, PacketPtr packetPtr);
  116. void             DoReceiveData(MyEndpointRef *myEp);
  117. OSStatus         DoSndDisconnect(MyEndpointRef *myEp);
  118. OSStatus         DoDisconnect(MyEndpointRef *myEp);
  119. OSStatus         DoRcvDisconnect(MyEndpointRef *myEp);
  120. OSStatus         DoRcvOrderlyDisconnect(MyEndpointRef *myEp);
  121. OSStatus         PollQueueList(void);
  122. OSErr             ProcessIncomingDataFile(MyEndpointRef *theEp, PacketPtr packetPtr);
  123. Boolean         TestDataIsPSQuery(PacketPtr packetPtr);
  124. OSStatus         ProcessPSQuery(PacketPtr packetPtr);
  125. Boolean            DoProcessPSQuery(PacketPtr packetPtr);
  126. OSErr             CheckFileToClose(void);
  127. void            DoServer(void);
  128. void            DoEvent(EventRecord *event);
  129. OSStatus         DoOTUnbind(MyEndpointRef *theEp);
  130. OSStatus         DoBind(EndpointRef ep, UInt8 socket, UInt8 type, OTQLen qlen, 
  131.                         char *nbpName, UInt32 nbpNameLen);
  132. OSStatus         StartAbortiveDisconnect(MyEndpointRef *myEp);
  133. OSStatus         ActivatePAPEndpoint(MyEndpointRef *myEp);
  134. OSStatus         ActivateHandoffEndpoint(MyEndpointRef *myEp);
  135. OSStatus         InitPAPServerStuff(void);
  136. void            ClosePAPServerStuff(void);
  137. OSStatus            InitMyEndpointRef(MyEndpointRef *myEp);
  138. OSStatus         InitPAPBuffers(void);
  139. void             ReleasePAPMemory(void);
  140. extern OSStatus DoNegotiateEOMOption(EndpointRef ep, Boolean enableEOM);
  141. extern OSStatus DoSetServerStatusOption(EndpointRef ep, char *statusStr);
  142. extern OSStatus DoNegotiateSelfSendOption(EndpointRef ep, long enableSelfSend);
  143. void             DoValueBreak(long value, const char* message);
  144. OSStatus         BeginSetServerStatusOption(EndpointRef ep, UInt16 whichStr);
  145. UInt32             GetYesNoOption(void);
  146. Boolean         EndpointsAllBusy(void);
  147. #if HANDOFF_EP
  148. MyEndpointRef*    FindFreeHandoffEp(void);
  149. #endif
  150.  
  151.  
  152. static pascal void OTDebugStr(const char *msg)
  153. {
  154.     UInt8 pMsg[256];
  155.     
  156.     pMsg[0] = OTStrLength(msg);
  157.     OTMemcpy(&pMsg[1], msg, pMsg[0]);
  158.     DebugStr(pMsg);
  159. }
  160.  
  161.  
  162. /*******************************************************************************
  163. ** EventHandler
  164. **  The event handler can be called at times when it is not safe to do console I/O,
  165. **  so this routine takes the event and jams it on a list to be handled when
  166. **  we know it's safe to print informative messages
  167. ********************************************************************************/
  168.  
  169. pascal void EventHandler(void* contextPtr, OTEventCode code,
  170.                                         OTResult result, void* cookie)
  171. {
  172. #pragma unused (cookie)
  173.     
  174.     
  175.     switch (code)
  176.     {
  177.         case T_LISTEN:                /* An connection request is available     */
  178.             SetListenPendFlag(((MyEndpointRef*)contextPtr)->flags);
  179.             DoListenAccept(contextPtr);
  180.             break;
  181.             
  182.         //    T_DATA:
  183.         //
  184.         //    The main rule for processing T_DATA's is to remember that once you have
  185.         //    a T_DATA, you won't get another one until you have read to a kOTNoDataErr.
  186.         //    The advanced rule is to remember that you could get another T_DATA
  187.         //    during an OTRcv() which will eventually return kOTNoDataErr, presenting
  188.         //    the application with a synchronization issue to be most careful about.
  189.         //    
  190.         //    In this application, since an OTRcv() calls are made from inside the notifier,
  191.         //    this particular synchronization issue doesn't become a problem.
  192.         //
  193.         case T_DATA:                /* Standard data is available            */
  194.                                     // check that we are in the DATAXFER state
  195.             SetHasDataFlag(((MyEndpointRef*)contextPtr)->flags);
  196.             if (TstPassconFlag(((MyEndpointRef*)contextPtr)->flags))
  197.                 DoReceiveData(contextPtr);
  198.             break;
  199.  
  200.         case T_DISCONNECT:            /* A disconnect is available            */
  201.                 // check whether there is a file open on this endpoint
  202.             DoRcvDisconnect(contextPtr);
  203.             break;
  204.             
  205.         case T_ERROR:                /* obsolete/unused in library            */
  206.         case T_UDERR:                /* A Unit Data Error has occurred        */
  207.             OTDebugStr((const char *)"T_ERROR called;g");
  208.             break;
  209.  
  210.         case T_ORDREL:                /* An orderly release is available        */
  211.             DoRcvOrderlyDisconnect(contextPtr);
  212.             break;
  213.  
  214.         case T_GODATA:                /* Flow control lifted on standard data    */
  215.                                     // for this sample, I do not expect this event to occur.
  216.             OTDebugStr((const char *)"T_GODATA called;g");
  217.             break;
  218.  
  219.         case T_GOEXDATA:            /* Flow control lifted on expedited data*/
  220.                                     // for this sample, I do not expect this event to occur.
  221.             OTDebugStr((const char *)"T_GOEXDATA called;g");
  222.             break;
  223.  
  224.         case T_PASSCON:                /* State is now case T_DATAXFER            */
  225.                     // set the passcon flag
  226.                 // set flag to indicate that the endpoint is busy
  227.             SetEPBusyFlag(((MyEndpointRef*)contextPtr)->flags);
  228.                 // Set flag to indicate that the endpoint is bound
  229.                 // RRK addition 3/10/99
  230.             SetEPBoundFlag(((MyEndpointRef*)contextPtr)->flags);
  231.                 // set flag to tell system to set server status flag appropriately
  232.                 // for multiple handoff endpoint servers, this would need to be
  233.                 // handled differently.
  234.             SetCheckOptFlag(gFlags);
  235.  
  236.             SetFirstPktFlag(((MyEndpointRef*)contextPtr)->flags);
  237.  
  238.             SetPassconFlag(((MyEndpointRef*)contextPtr)->flags);
  239.  
  240.                         // Set the timer for this connection
  241.             OTGetTimeStamp(&((MyEndpointRef*)contextPtr)->timerDog);
  242.  
  243.                     // check to see if there is any data to process
  244.             DoReceiveData(contextPtr);
  245.             break;
  246.             
  247.         case T_RESET:                /* Protocol has been reset                */
  248.             OTDebugStr((const char *)"T_RESET called;g");
  249.             break;
  250.  
  251.         case T_ACCEPTCOMPLETE:        /* Accept call is complete                */
  252.             OTDebugStr((const char *)"T_ACCEPTCOMPLETE called;g");
  253.             ClrAcceptPendFlag(((MyEndpointRef*)contextPtr)->flags);
  254.             SetFirstPktFlag(((MyEndpointRef*)contextPtr)->flags);
  255.             
  256.                 // RRK 3/9/99
  257.                 // check for an error result
  258.             if (result != kOTNoError)
  259.             {
  260.                 OTDebugStr("Error occured with T_ACCEPTCOMPLETE event");
  261.                 if (result == kOTLookErr )
  262.                 {
  263.                     HandleOTLookErr(contextPtr);
  264.                 }
  265.             }
  266.             break;
  267.  
  268.         case T_DISCONNECTCOMPLETE:    /* Disconnect call is complete            */
  269.             OTDebugStr("T_DISCONNECTCOMPLETE event occurred;g");
  270.             ClrDisconPendFlag(((MyEndpointRef*)contextPtr)->flags);    // is the server endpoint bound
  271.             ClrEPBusyFlag(((MyEndpointRef*)contextPtr)->flags);
  272.             ClrAcceptPendFlag(((MyEndpointRef*)contextPtr)->flags);
  273.             ClrListenPendFlag(((MyEndpointRef*)contextPtr)->flags);
  274.  
  275.             break;
  276.         
  277.         case T_UNBINDCOMPLETE:                                        // RRK 3/9/99 add code to protect against multiple unbind calls
  278. //            OTDebugStr((const char *)"T_UNBINDCOMPLETE called;g");
  279.             DoValueBreak((long)contextPtr, "T_UNBINDCOMPLETE called #");
  280.             SetCheckOptFlag(gFlags);                                // set flag to force the server to determine
  281.                                                                     // whether to change the server message
  282.             ClrEPBusyFlag(((MyEndpointRef*)contextPtr)->flags);        // no longer waiting for T_UNBINDCOMPLETE message
  283.             ClrUnbindPendFlag(((MyEndpointRef*)contextPtr)->flags);
  284.             ClrEPBoundFlag(((MyEndpointRef*)contextPtr)->flags);    // is the server endpoint bound
  285.  
  286.             SetStatusIdleFlag(gFlags);
  287.             break;
  288.             
  289.         //
  290.         //    kStreamIoctlEvent:
  291.         //
  292.         //    This event is returned when an I_FLUSH ioctl has completed.
  293.         //    The flush was done in an attempt to get back all T_MEMORYRELEASED events
  294.         //    for outstanding OTSnd() calls with Ack Sends.   Errors are ignored at this point since it is
  295.         //    possible that the connection will already be gone, etc.
  296.         //
  297.         case kStreamIoctlEvent:        // the flush is complete
  298.             DoSndDisconnect (contextPtr); /* safe to disconnect */
  299.             break;
  300.         
  301.         case T_OPTMGMTCOMPLETE:
  302.             if (result != kOTNoError)
  303.             {
  304.                 OTDebugStr("Error occured with T_OPTMGMTCOMPLETE event");
  305.             }
  306.             
  307.             gOptionCompleted = 1;
  308.             break;
  309.  
  310.         default:
  311.             break;
  312.     }
  313. }
  314.  
  315. /***********************************************************
  316.     RRK 3/9/99 addition
  317.     HandleOTLookErr implemented to handle OTLookErr in a
  318.     central place - only call this function in response
  319.     to a OTLookErr for a function call
  320.     
  321. ************************************************************/
  322. OSStatus HandleOTLookErr(MyEndpointRef *myEp)
  323. {
  324.     OSStatus        err = kOTNoError;
  325.     OTResult        result;
  326.     
  327.     result = OTLook(myEp->ep);
  328.     
  329.     switch (result)
  330.     {
  331.         case T_DISCONNECT:
  332.             err = DoRcvDisconnect(myEp);
  333.             if (err == kOTNoError)
  334.             {
  335.                 ClrInPSQueryFlag(myEp->flags);
  336.             }
  337.             else
  338.             {
  339.                 DoValueBreak(err, "Error calling DoRcvDisconnect from HandleOTLookErr #");
  340.                 SetForceCloseFlag(myEp->flags);
  341.             }
  342.  
  343.             break;
  344.         
  345.         case T_ORDREL:
  346.             err = DoRcvOrderlyDisconnect(myEp);
  347.                 // if successful, then we enter T_INREL state
  348.             if (err != kOTNoError)
  349.             {
  350.                 DoValueBreak(err, "Error calling DoRcvOrderlyDisconnect from HandleOTLookErr #");
  351.                 SetForceCloseFlag(myEp->flags);
  352.             }
  353.             break;
  354.             
  355.         
  356.         default:
  357.                 // The use of this function in this instance is to handle
  358.                 // T_DISCONNECT events that can happen.  This call will
  359.                 // need to be customized for other use, like handling 
  360.                 // T_DATA events which is not implemented in this sample.
  361.                 // Pass a debugStr call to show what event was not handled here
  362.             DoValueBreak((long)result, "HandleOTLookErr passed unprocessed event - #");
  363.             
  364.             break;
  365.         
  366.     }
  367.     
  368.     return err;
  369. }
  370.  
  371. //
  372. //    EnterListenAccept
  373. //
  374. //    This is a front end to DoListenAccept() which is used whenever 
  375. //    it is not being called from inside the listener endpoint's notifier.
  376. //    We do this for syncrhonization.   If we were processing an OTListen()
  377. //    or an OTAccept() and we were interrupted at the listener endpoint's
  378. //    notifier with a T_LISTEN, etc, it would be inconvenient and would require
  379. //    some more sophisticated synchronization code to deal with the problem.
  380. //    The easy way to avoid this is to do an OTEnterNotifier() on the listener's
  381. //    endpoint.   
  382. //
  383. //    Important note - doing OTEnterNotifier on one endpoint only prevents that
  384. //    endpoint's notifier for interrupting us.   Since the same notifier code
  385. //    is used for lots of endpoints here, remember that the one endpoint's 
  386. //    notifier can interrupt another.   Doing an OTEnterNotifier() on the
  387. //    listener endpoint prevents the listener from interrupting us, but it
  388. //    does not prevent the Notifier() routine from interrupting us via 
  389. //    another endpoint which also uses the same routine.
  390. //
  391. //    Important note #2 - Don't ever do an OTEnterNotifier on an acceptor endpoint
  392. //    before doing the OTAccept().   This confuses OT and creates problems.
  393. //
  394. static void EnterListenAccept(MyEndpointRef *myServerEp)
  395. {
  396.     Boolean    doLeave;
  397.     
  398.     doLeave = OTEnterNotifier(myServerEp->ep);
  399.     DoListenAccept(myServerEp);
  400.     if (doLeave)
  401.         OTLeaveNotifier(myServerEp->ep);
  402. }
  403.  
  404. /*
  405.     DoListenAccept is designed to handle an incoming connect request.  This module demonstrates a
  406.     very complex task that all X/OPEN style acceptors must implement.  The problem stems from
  407.     fact that an endpoint may be hit by a number of simultaneous connect requests.  In addition
  408.     if there is a connection already established and the endpoint handles multiple
  409.     handoff endpoints, then there could also be an incoming disconnect request to process before
  410.     one can issue either an Accept or Disconnect response, all pending Connect requests must
  411.     be consumed from the streamhead first.  This places a burden on the accept routine to have
  412.     a place to temporarily stash all of the addresses to which discon messages will have to be
  413.     sent.
  414.     
  415.     Refer to Tech Note 1059 for the 8 steps to handling an incoming connection request.
  416.     
  417.     Note that once all of the connect request have been consumed and we are in the process of
  418.     sending discon responses, it could be that there will again be an kOTLookErr, which
  419.     indicates that another incoming connect request heeds to be consumed before
  420.     resuming with the discon responses.
  421.     
  422.     In this sample we consume the first listen request.  We then check whether we can accept
  423.     the incoming request, If so, then call OTAccept.  If OTAccept fails with a lookErr, then 
  424.     there is another connect request to be consumed.
  425.     
  426.     processed.
  427.     
  428. */
  429. void DoListenAccept(MyEndpointRef *myServerEp)
  430. {
  431.     MyEndpointRef    *myAcceptEp;
  432.     OSStatus    err;
  433.     TCall        call;
  434.     Boolean        done = false;
  435.     
  436.         // check we have already entered DoListenAccept from the main event loop and are 
  437.         // trying to do so again from the secondary interrupt
  438.     if (OTAtomicSetBit(&myServerEp->semaphore, kInListenLoop))
  439.         return;    // if the bit was previous set, then we already have entered, but not exitted
  440.                 // this proc from the main event loop
  441.  
  442.     if (TstAcceptPendFlag(myServerEp->flags))
  443.     {
  444.             // we're waiting for an Accept call to complete, so don't accept a new
  445.             // connection request as we will get an out of state error
  446.             // set the ListenPendFlag so we will check the server endpoint later
  447.         
  448.         SetListenPendFlag(myServerEp->flags);
  449.         done = true;
  450.     }
  451.     else
  452.         ClrListenPendFlag(myServerEp->flags);
  453.     
  454.     if (done == false)
  455.     {
  456.             // clear out the TCall structure
  457.         memset(&call, 0, sizeof(TCall));
  458.         
  459.             // set up the TCall structure
  460.         call.addr.maxlen = sizeof(struct DDPAddress);
  461.         call.addr.len = sizeof(struct DDPAddress);
  462.         call.addr.buf = (unsigned char *) &gAddr;
  463.                 
  464.         if (OTIsSynchronous(myServerEp->ep) == true)
  465.             OTSetAsynchronous(myServerEp->ep);
  466.             
  467.             // step 1 for handling an incoming connection request
  468.         err = OTListen(myServerEp->ep, &call);
  469.         
  470.         if (err == kOTNoDataErr)
  471.         {
  472.             OTDebugStr((const char*)"kOTNoDataErr returned by OTListen");
  473.                 // don't need to do anything
  474.         }
  475.         else if (err == kOTLookErr)
  476.         {
  477.                 // step 2 for handling incoming connection requests
  478.                 // handle disconnect indications for a pending connection request
  479.                 // the only look indication allowed on an OTListen call is
  480.                 // T_DISCONNECT
  481.             HandleOTLookErr(myServerEp);
  482.             done = true;
  483.              
  484.         }
  485.         else if (err != kOTNoError) // there was an unknown error in doing the listen
  486.         {
  487.             DoValueBreak((long)err, "error occured on OTListen #");
  488.             done = true;
  489.  
  490.         }
  491.     }
  492.     
  493.     if (done == false)
  494.     {
  495. #if HANDOFF_EP
  496.         myAcceptEp = FindFreeHandoffEp();
  497. #else
  498.         if (TstEPBusyFlag(myServerEp.flags) == false)
  499.             myAcceptEp = myServerEp;
  500.         else
  501.             myAcceptEp = nil;
  502. #endif         
  503.     }
  504.     
  505.     if (myAcceptEp == nil)
  506.     {
  507.             OTDebugStr((const char *)"rejecting T_LISTEN - no free handoff endpoints");
  508.             // if there are no available handoff endpoints, then send the disconnect
  509.         OTSndDisconnect(myServerEp->ep, &call);
  510.         done = true;
  511.     }
  512.     
  513.     if (done == false)
  514.     {
  515.     
  516.             // set a flag to indicate that an accept call is pending
  517.             // if we try to accept another connection before this
  518.             // accept call is completed, an out of state error results 
  519.             // need to do this before we make the OTAccept call
  520.         SetAcceptPendFlag(myServerEp->flags);
  521.         
  522.             // make the accept call and handoff the connection
  523.         err = OTAccept(myServerEp->ep, myAcceptEp->ep, &call);
  524.  
  525.         if (err == kOTNoError)
  526.         {
  527.             SetEPBusyFlag(myAcceptEp->flags);
  528.  
  529.                 // set flag to have server check the serverstatus
  530.             TstCheckOptFlag(gFlags);
  531.                         
  532.         }
  533.         else if (err == kOTLookErr)
  534.         {
  535.             HandleOTLookErr(myServerEp);
  536.         }
  537.         else
  538.         {
  539. #if HANDOFF_EP
  540.             DoValueBreak((long)err, "error occured on OTAccept for handoff #");
  541. #else
  542.             DoValueBreak((long)err, "error occured on OTAccept #");
  543. #endif
  544.  
  545.         }
  546.     }
  547.     
  548.         
  549.     OTAtomicClearBit(&myServerEp->semaphore, kInListenLoop);    // clear the bit that indicates we're in this loop
  550.     
  551. }
  552.  
  553. /*******************************************************************************
  554. ** ReceiveOnePacket - makes the call to receive just one packet
  555. ** If there is data, then the data is placed into the packetPtr
  556. ** and the incoming byte count is incremented
  557. ** if the kOTNoDataErr occurs, then the HasDataFlag is cleared.
  558. ** 
  559. **   
  560. ********************************************************************************/
  561. Boolean ReceiveOnePacket(MyEndpointRef *myEp, PacketPtr packetPtr)
  562. {
  563.     OTResult     result;
  564.     Boolean        done = false;
  565.                     
  566.     result = OTRcv(myEp->ep, &packetPtr->data, kPAPDataSize, &packetPtr->flags);
  567.     if (result < 0)
  568.     {
  569.             // requeue the buffer to the freeq
  570.         OTLIFOEnqueue(gFreeQ, &(packetPtr->fLink));
  571.         done = true;
  572.         
  573.         if (result == kOTLookErr)
  574.         {
  575.             HandleOTLookErr(myEp->ep);
  576.             
  577.         }
  578.         else if (result == kOTOutStateErr)
  579.         {
  580.                 // client could have issued a disconnect call while this call was about to
  581.                 // to be processed
  582.             ClrHasDataFlag(myEp->flags);
  583.         }
  584.         
  585.         else if (result == kOTNoDataErr)
  586.         {
  587.                 // no more data so clr the flag
  588.             ClrHasDataFlag(myEp->flags);
  589.         }
  590.         else 
  591.         {
  592.             DoValueBreak(result, "Unknown error occurred in OTRcv #");
  593.         }
  594.     }
  595.     else if (result == 0)
  596.     {
  597.         OTDebugStr((const char *)"OTRcv got nothing ;g");
  598.         
  599.         if (TstInPSQueryFlag(myEp->flags))    // check if the endpoint is already processing a postscript
  600.         {
  601.             OTDebugStr((const char *)"0 byte packet while processing ps query ;g");
  602.  
  603.             if (packetPtr->flags & T_MORE == 0)
  604.                 OTDebugStr((const char *)"T_MORE was not set;g");
  605.             else
  606.                 OTDebugStr((const char *)"T_MORE was set;g");
  607.                 
  608.                 // send an empty response with EOF flags set since it appears that this is what the Laserwriter 
  609.                 // client wants to see. At this point, we have already processed any preceding 
  610.                 // ps queries.  It is important to not respond with an empty packet and EOF bit set if
  611.                 // there is still a ps query response outstanding.
  612.             packetPtr->theEp = myEp;
  613.             SendEmptyPacket(packetPtr);
  614.                 // clear bit that indicates we are processing a postscript query
  615.             ClrInPSQueryFlag(myEp->flags);
  616.     
  617.             OTDebugStr((const char *)"Have finished ps query;g");
  618.             
  619.                 // queue the buffer to the freeQ associated with the endpoint
  620.             OTLIFOEnqueue(gFreeQ, &(packetPtr->fLink));
  621.         }
  622.         else
  623.         {
  624.             
  625.                 // pass this packet on to the event loop so that we can send a null response
  626.                 // save the endpoint ref associated with this data.
  627.                 // While we could send the empty packet here, this example waits until the
  628.                 // data is processed in the main event loop to send the null packet.
  629.             packetPtr->theEp = myEp;
  630.             
  631.                         // save the amount of data read 
  632.             packetPtr->numBytes = result;
  633.             
  634.                         // intialize the lastPos field
  635.             packetPtr->lastPos = 0;
  636.             
  637.                         // get the timestamp for this packet
  638.             OTGetTimeStamp(&packetPtr->timeStamp);
  639.             
  640.                         // Set the timer for this connection
  641.             OTGetTimeStamp(&myEp->timerDog);
  642.  
  643.                 // queue the buffer to the usedQ associated with the endpoint
  644.             OTLIFOEnqueue(myEp->usedQ, &(packetPtr->fLink));
  645.         }
  646.             
  647.         
  648.     }
  649.     else
  650.     {
  651.             // check if this is the first packet for this endpoint and set the time in timestamp
  652.         if (TstFirstPktFlag(myEp->flags))
  653.         {
  654.             ClrFirstPktFlag(myEp->flags);
  655.                 
  656.                 // set the time Data In timestamp field
  657.             OTGetTimeStamp(&myEp->timeDataIn);
  658.             
  659.                 // zero out the numByteIn field
  660.             myEp->numBytesIn = 0;
  661.             
  662.         }
  663.             // save the number of bytes read
  664.         myEp->numBytesIn += result;
  665.  
  666.             // set the time data end timestamp field
  667.         OTGetTimeStamp(&myEp->timeDataEnd);
  668.  
  669.         if (TstdumpAllPktsFlag(gFlags))
  670.         {
  671.             OTLIFOEnqueue(gFreeQ, &(packetPtr->fLink));
  672.         }
  673.         else
  674.         {
  675.             
  676.                         // save the endpoint ref associated with this data
  677.             packetPtr->theEp = myEp;
  678.             
  679.                         // save the amount of data read 
  680.             packetPtr->numBytes = result;
  681.             
  682.                         // intialize the lastPos field
  683.             packetPtr->lastPos = 0;
  684.             
  685.                         // get the timestamp for this packet
  686.             OTGetTimeStamp(&packetPtr->timeStamp);
  687.             
  688.                         // Set the timer for this connection
  689.             OTGetTimeStamp(&myEp->timerDog);
  690.             
  691.             if (!DoProcessPSQuery(packetPtr))
  692.             {
  693.                     // packet is not a postscript query so queue to the endpoint usedQ
  694.                     // queue the buffer to the usedQ associated with the endpoint
  695.                 OTLIFOEnqueue(myEp->usedQ, &(packetPtr->fLink));
  696.                 
  697.             }
  698.         
  699.         }
  700.  
  701.     }
  702.     
  703.     return done;
  704.         
  705. }
  706.  
  707.  
  708. /*******************************************************************************
  709. ** DoReceiveData
  710. **   
  711. ********************************************************************************/
  712. void DoReceiveData(MyEndpointRef *myEp)
  713. {
  714.     PacketPtr    packetPtr;
  715.     OTFlags        flags = 0;
  716.     Boolean        done;
  717.     
  718.         // check we have already entered DoReceiveData from the main event loop
  719.         // or from the event handler and are 
  720.         // trying to do so again a second time
  721.     if (OTAtomicSetBit(&myEp->semaphore, kInRcvDataFlag))
  722.         return;    // if the bit was previous set, then we already have entered, but not exitted
  723.                 // this proc from the main event loop
  724.  
  725.     done = gDone;
  726.     while (done == false)
  727.     {
  728.         if (gFreeQ->fHead != nil)
  729.         {
  730.             packetPtr = (PacketPtr)OTLIFODequeue(gFreeQ);
  731.             done = ReceiveOnePacket(myEp, packetPtr);
  732.         }
  733.         else
  734.         {
  735.             
  736.             done = true;
  737.         }
  738.             
  739.         
  740.     }
  741.  
  742.     OTAtomicClearBit(&myEp->semaphore, kInRcvDataFlag);    
  743.                 // clear the bit that indicates we're in this loop
  744.                         
  745. }
  746.  
  747. OSStatus DoSndDisconnect(MyEndpointRef *myEp)
  748. {
  749.     OSStatus        err;
  750.  
  751.     err = OTSndDisconnect(myEp->ep, NULL);
  752.     if (err != kOTNoError)
  753.     {
  754.         DoValueBreak((long)err, "error occured on OTSndDisconnect #");
  755.     }
  756.     else
  757.     {
  758.         ClrAcceptPendFlag(myEp->flags);
  759.     }
  760.  
  761.     return err;
  762. }
  763.  
  764.  
  765. OSStatus DoRcvDisconnect(MyEndpointRef *myEp)
  766. {
  767.     OSStatus        err = kOTNoError;
  768.     
  769.     if (TstDisconPendFlag(myEp->flags))
  770.     {
  771.             // set discon flag before making the call and clear it if the call
  772.             // fails so that we don't have a race condition with the handler routine
  773.         SetDisconPendFlag(myEp->flags);
  774.         err = OTRcvDisconnect(myEp->ep, NULL);
  775.         if (err != kOTNoError)
  776.         {
  777.             DoValueBreak((long)err, "error occured on OTRcvDisconnect #");
  778.             ClrDisconPendFlag(myEp->flags);
  779.         }
  780.     }
  781.  
  782.     return err;
  783. }
  784.  
  785. OSStatus DoRcvOrderlyDisconnect(MyEndpointRef *myEp)
  786. {
  787.     OSStatus        err;
  788.     
  789.     err = OTRcvOrderlyDisconnect(myEp->ep);
  790.     if (err < kOTNoError)
  791.     {
  792.         DoValueBreak((long)err, "error occured on OTRcvOrderlyDisconnect #");
  793.     }
  794.     else if (err > 0)
  795.     {            
  796.         OTDebugStr((const char *)"OTRcvOrderlyDisconnect returned positive result;g");
  797.     }
  798.     
  799.     return err;
  800. }
  801.  
  802. /*******************************************************************************
  803. ** PollEventList
  804. **  This routine checks the used queue to see whether the handler has processed
  805.     incoming PAP data from the client.
  806. **    If the used queue is not empty, there are two different options to deal with.
  807.     First we check whether we are in the middle of processing a postscript data
  808.     file.  If so, we continue to read the data into a file which we have created.
  809.     If not currently processing postscript data, we then check to see if the incoming
  810.     packet is part of a postscript query in progress or is the beginning of a 
  811.     postscript query.  If so, we continue to read the query and respond as appropriate.
  812.     If not a query, then this must be the first packet of postscript data being sent.
  813.     
  814. ********************************************************************************/
  815.  
  816. OSStatus PollQueueList(void)
  817. {
  818.     PacketPtr    packetPtr, nextPacketPtr;
  819.     MyEndpointRef *theEp;
  820.     OSStatus    err = kOTNoError;
  821.     short        i = 0;
  822.     Boolean        done = false;
  823.     
  824. #if HANDOFF_EP
  825.     for (i = 0; (i < kMaxHandoffEPs) && (err == kOTNoError); i++)
  826.     {
  827.         theEp = &gHandoffEp[i];
  828. #else
  829.         theEp = &gEp;
  830. #endif
  831.  
  832.         packetPtr = (PacketPtr)OTLIFOStealList(theEp->usedQ);
  833.         while (packetPtr != nil)
  834.         {
  835.  
  836.             packetPtr = (PacketPtr)OTReverseList((OTLink*)packetPtr);
  837.             do
  838.             {
  839.                 nextPacketPtr = (PacketPtr)packetPtr->fLink.fNext;
  840.                 
  841.                 err = ProcessIncomingDataFile(theEp, packetPtr);
  842.         
  843.                     // queue the packetPtr back to the freeQ
  844.                 OTLIFOEnqueue(gFreeQ, &(packetPtr->fLink));
  845.  
  846.                 packetPtr = nextPacketPtr;
  847.                 
  848.             } while((packetPtr != nil) && (err == kOTNoError));
  849.             
  850.             packetPtr = (PacketPtr)OTLIFOStealList(theEp->usedQ);
  851.         }
  852.  
  853. #if HANDOFF_EP
  854.     }
  855. #endif
  856.                     
  857.     return err;
  858. }
  859.  
  860. OSErr ProcessIncomingDataFile(MyEndpointRef *theEp, PacketPtr packetPtr)
  861. {
  862.     OSStatus        err = noErr;
  863.     short            fRefNum;
  864.     Boolean            eofFlag = false;
  865.     
  866.     
  867.         // For each incoming packet, we need to check whether the EOF
  868.         // bit was set by looking at whether the T_MORE flag was clear
  869.  
  870.     if ((packetPtr->flags & T_MORE) == 0)
  871.     {
  872.         fprintf(stdout, "\nT_MORE flag not set \n");
  873.         if (TstEOMOnFlag(theEp->flags))
  874.         {
  875.                 // send empty packet response to the sender to acknowledge that we
  876.                 // have received the last packet
  877.                 // this is 
  878.             fprintf(stdout, "Sending empty response packet \n");
  879.             SendEmptyPacket(packetPtr);
  880.             eofFlag = true;
  881.         }
  882.         else
  883.         {
  884.             fprintf(stdout, "EOM option not enabled - cannot tell if EOF message sent \n");
  885.         }
  886.     }
  887.         
  888.     if (!TstdumpAllPktsFlag(gFlags) && !TstDumpPktsFlag(theEp->flags))    // check if we are dumping the packets
  889.     {
  890.         if (!TstTempFileFlag(theEp->flags)) // is there a temp file opened for this endpoint
  891.         {
  892.                 // no, so create one
  893.             err = OpenTempFile(&fRefNum);
  894.             if (err == noErr)
  895.             {
  896.                 fprintf(stdout, "\nprocessing incoming file\n");
  897.                 theEp->fRefNum = fRefNum;        // save the refnum of the temp file;
  898.                 SetTempFileFlag(theEp->flags);    // indicate that there is a temp file associated
  899.                                                 // with this endpoint.
  900.             }
  901.             else
  902.             {
  903.                 fprintf(stdout, "Error occurred opening a temp file %d\n", err);
  904.                 fprintf(stdout, "The packets will be dumped%d\n", err);
  905.             }
  906.             
  907.         }
  908.  
  909.         if (err == noErr)
  910.         {
  911.             
  912.                 // the temp file has been created or already exists, so read the data and write it
  913.                 // to the temp file
  914.             err = WriteDataToTempFile(theEp->fRefNum, packetPtr->data, packetPtr->numBytes);
  915.             if (err != noErr)
  916.             {
  917.                 fprintf(stdout, "Error occurred writing to temp file %d\n", err);
  918.                 fprintf(stdout, "All remaining packets will be dumped for this endpoint\n");
  919.                 SetDumpPktsFlag(theEp->flags);
  920.                     // set err to noErr otherwise the error would force the close of the
  921.                     // program
  922.                 err = noErr;    
  923.             }
  924.                 // check if the eof bit was set, and close the file if so
  925.             if (eofFlag == true)
  926.             {
  927.                 err = CloseTempFile(theEp->fRefNum);
  928.                 if (err != noErr)
  929.                     fprintf(stdout, "\n\nError occurred closing file - error %ld.\n", err);        
  930.                 else
  931.                     ClrTempFileFlag(theEp->flags);
  932.             }
  933.         }
  934.     }
  935.     
  936.     return err;
  937. }
  938.  
  939.  
  940. OSErr CheckFileToClose(void)
  941. {
  942.     OSErr    err = noErr;
  943.     
  944.     if (gFRefNumToClose != 0)
  945.     {
  946.         fprintf(stdout, "Am about to close file with fRefNum %ld.\n", gFRefNumToClose);
  947.         
  948.         err = CloseTempFile(gFRefNumToClose);
  949.         if (err != noErr)
  950.             fprintf(stdout, "\n\nError occurred closing file - error %ld.\n", err);        
  951.         
  952.             // reset the tempfile to close so that we don't close this file again
  953.         gFRefNumToClose = 0;
  954.     }
  955.     
  956.     return err;
  957. }
  958.  
  959.  
  960. /*******************************************************************************
  961. ** DoServer
  962. ********************************************************************************/
  963.  
  964. void DoServer(void)
  965. {
  966.     EventRecord        theEvent;
  967.     OTTimeStamp        eTime;
  968.     OTResult        state;
  969.     UInt32            eTimeMSec, sec, msec, rate;
  970.     MyEndpointRef    *theEp;
  971.     OSStatus         err1, err = kOTNoError;
  972. #if HANDOFF_EP
  973.     short            i = 0;
  974. #endif
  975.     
  976.     while (gDone == false)
  977.     {
  978.         if (!WaitNextEvent(everyEvent, &theEvent, 15, nil))
  979.             theEvent.what = nullEvent;
  980.             
  981.         DoEvent(&theEvent);
  982.         
  983.         if (TstListenPendFlag(gEp.flags))        // are there incoming connect requests to process
  984.         {
  985.             fprintf(stdout, "\n processing EnterListenAccept from even tloop");
  986.             EnterListenAccept(&gEp);
  987.         }
  988.             
  989.         err = PollQueueList();
  990.         if (err != kOTNoError)        // we're outta here if an error occurred.
  991.             gDone = true;
  992.  
  993. #if HANDOFF_EP
  994.         theEp = &gHandoffEp[i];
  995.         i++;
  996.         if (i >= kMaxHandoffEPs)
  997.             i = 0;
  998. #else
  999.         theEp = &gEp;
  1000. #endif
  1001.         if (TstForceCloseFlag(theEp->flags))
  1002.         {
  1003.             state = kForceClose;
  1004.         }
  1005.         else
  1006.         {
  1007.                 // get the current endpoint state
  1008.             state = OTGetEndpointState(theEp->ep);
  1009.         }
  1010.         
  1011.         switch (state)
  1012.         {
  1013.             case T_DATAXFER:
  1014.                     
  1015.                     // check if we haven't completed reading data from OT.  
  1016.                 DoReceiveData(theEp);
  1017.                 break;
  1018.                 
  1019.             case T_INREL:    // we've processed an incoming Orderly Release request
  1020.                             // but have not issued our own orderly disconnect
  1021.                 
  1022.  
  1023.                     // note that since we have already processed an incoming orderly disconnect
  1024.                     // we are in the INREL state.  After making the OTSndOrderlyDisconnect
  1025.                     // call, there will not be a T_DISCONNECTCOMPLETE call, since we complete
  1026.                     // the orderly release with the above call.  We go ahead and reset our flags
  1027.                     // and issue the OTUnbind call if we are using a handoff endpoint.
  1028.                     // if we did get the orderly release indication, then make sure we have
  1029.                     // drained the receive queue - PollQueueList does this
  1030.                     
  1031.                     // A PAPServer does not normally issue an OrderlyDisconnect request.  Typically,
  1032.                     // the client issues the orderly release, at which point the server must accept the
  1033.                     // T_ORDREL event. At this point the server is 
  1034.  
  1035.  
  1036.                 do
  1037.                 {
  1038.                     fprintf(stdout, "processing some last data\n");
  1039.                     PollQueueList();
  1040.                 
  1041.                 }while( (TstHasDataFlag(theEp->flags)) || (theEp->usedQ->fHead != nil));
  1042.  
  1043.                 fprintf(stdout, "Calling OTSndOrderlyDisconnect\n");
  1044.                     // clear the flag and send a corresponding disconnect
  1045.                 err = OTSndOrderlyDisconnect(theEp->ep);
  1046.                 if (err)
  1047.                 {
  1048.                     // the only error that makes sense here is the kOTLookErr
  1049.                     //  which the only event is the T_DISCONNECT event.  This should not happen,
  1050.                     // however, if there are multiple handoffs, this may be an issue.  Given the way
  1051.                     // incoming requests are handled, I don't expect that there would be an 
  1052.                     // unresponded listen request here that would warrant a possible T_DISCONNECT
  1053.                     // however some implementation will need to consider this possibility.
  1054.                     DoValueBreak((long)err, "error occured on OTSndOrderlyDisconnect #");
  1055.                     
  1056.                     gDone = true;
  1057.  
  1058.                 }
  1059.                                         
  1060.                 if (TstTempFileFlag(theEp->flags))
  1061.                 {    
  1062.                                                         // is there an open spool file associated with this endpoint
  1063.                     gFRefNumToClose = theEp->fRefNum;    // set the global to have this file closed
  1064.                                                     // note that this method of signalling for a file to
  1065.                                                     // get closed is a quick and dirty method and assumes th
  1066.                                                     // that only one file at a time is being processed here.
  1067.                     CheckFileToClose();
  1068.                 }
  1069.                 
  1070.                 ClrTempFileFlag(theEp->flags);
  1071.                 ClrPassconFlag(theEp->flags);
  1072.  
  1073. #if HANDOFF_EP
  1074.                     // in order to re-use a handoff endpoint, it must be unbound.  Unbinding the 
  1075.                     // endpoint clears the connection information that allows to to know which
  1076.                     // endpoint, incoming PAP data is routed to.
  1077.                 if (theEp->ep != gEp.ep)
  1078.                 {
  1079.                     if (TstEPBoundFlag(theEp->flags))
  1080.                     {
  1081.                         OTDebugStr("Entered DoOTUnbind for T_INREL");
  1082.                         DoOTUnbind(theEp);        // RRK 3/9/99 change to protect against multiple unbinds
  1083.                     }
  1084.                 }
  1085. #else
  1086.                     // indicate that we are no longer busy
  1087.                 ClrEPBusyFlag(theEp->flags);
  1088.                     // set flag so that we will check the status
  1089.                 SetCheckOptFlag(gFlags);
  1090.                 SetStatusIdleFlag(gFlags);
  1091.                     
  1092. #endif
  1093.                     
  1094.                 
  1095.                     // calculate the elapsed time
  1096.                 OTSubtractTimeStamps(&eTime, &theEp->timeDataIn, &theEp->timeDataEnd);
  1097.                     // convert to millisecs
  1098.                 eTimeMSec = OTTimeStampInMilliseconds(&eTime);
  1099.                 sec = eTimeMSec / (UInt32)1000;
  1100.                 msec = eTimeMSec %(UInt32)1000;
  1101.                 fprintf(stdout, "Time to transfer file was %ld . %ld seconds.\n", sec, msec);
  1102.                 fprintf(stdout, "Bytes transferred was - %ld.\n", theEp->numBytesIn);
  1103.  
  1104.                 if (sec != 0)
  1105.                 {
  1106.                     rate = (theEp->numBytesIn / sec) / 1024;
  1107.                     fprintf(stdout, "Transfer rate - %ld KBytes/Sec. \n", rate);
  1108.                 }
  1109.                 else 
  1110.                 {
  1111.                     rate = (theEp->numBytesIn *1000 / msec) / 1024;
  1112.                     fprintf(stdout, "Transfer rate - %ld KBytes/Sec. \n", rate);
  1113.                 }
  1114.                 break;
  1115.                 
  1116.             case T_IDLE:    // we're either really idle, or the we've processed a disconnect event
  1117.                             // if we processed a disconnect event then the busy flag for the ep would still be set
  1118.                 fprintf(stdout, "i");
  1119.                 fflush(stdout);
  1120.                 
  1121.                 if (TstEPBusyFlag(theEp->flags))    // we're we previously connected
  1122.                 {
  1123.                     ClrPassconFlag(theEp->flags);    // clear the flag so that we can accept a new connection
  1124.                     
  1125.                     ClrTempFileFlag(theEp->flags);
  1126.                     ClrPassconFlag(theEp->flags);
  1127.  
  1128.                     if (TstTempFileFlag(theEp->flags))    
  1129.                                                             // is there an open spool file associated with this endpoint
  1130.                         gFRefNumToClose = theEp->fRefNum;    // set the global to have this file closed
  1131.                                                         // note that this method of signalling for a file to
  1132.                                                         // get closed is a quick and dirty method and assumes th
  1133.                                                         // that only one file at a time is being processed here.
  1134.  
  1135. #if HANDOFF_EP
  1136.                         // in order to re-use a handoff endpoint, it must be unbound.  Unbinding the 
  1137.                         // endpoint clears the connection information that allows to to know which
  1138.                         // endpoint, incoming PAP data is routed to.
  1139.                     if (theEp->ep != gEp.ep)
  1140.                     {
  1141.                         DoOTUnbind(theEp->ep);    // RRK 3/9/99 change to protect against multiple unbinds
  1142.         
  1143.                     }
  1144. #else
  1145.                         // set flag so that we will check the status
  1146.                     SetCheckOptFlag(gFlags);
  1147.                         // indicate that we are no longer busy
  1148.                     ClrEPBusyFlag(theEp->flags);
  1149.                     SetStatusIdleFlag(gFlags);
  1150.  
  1151. #endif
  1152.                 }
  1153.                 break;
  1154.             
  1155.             case kForceClose:    // our endpoint is really hosed so close it an reopen it
  1156.                 ClrForceCloseFlag(theEp->flags);
  1157.                 OTCloseProvider(theEp->ep);
  1158. #if HANDOFF_EP
  1159.                 err = ActivateHandoffEndpoint(theEp);
  1160. #else
  1161.                 err = ActivatePAPEndpoint(theEp);
  1162. #endif
  1163.                 if (err != kOTNoError)
  1164.                 {
  1165.                     fprintf(stdout, "\n Error activating endpoint - %ld.\n", err);
  1166.                     fprintf(stdout, "\n Quitting.\n");
  1167.                     gDone = true;
  1168.                 }
  1169.                 break;
  1170.                 
  1171.         }
  1172.         
  1173.         
  1174.         err1 = CheckFileToClose();
  1175.         if (err1 != noErr)
  1176.             fprintf(stdout, "\n\nCheckFileToClose error - %ld.\n", err1);
  1177.     
  1178.         if (TstCheckOptFlag(gFlags))
  1179.         {
  1180.             
  1181.             if (EndpointsAllBusy())
  1182.             {
  1183.                 if (TstStatusBusyFlag(gFlags) == false)
  1184.                 {
  1185.                     BeginSetServerStatusOption(gEp.ep, kSetBusyStr);
  1186.                     SetStatusBusyFlag(gFlags);
  1187.                 }
  1188.             }
  1189.             else
  1190.             {
  1191.                 if (TstStatusBusyFlag(gFlags) == true)
  1192.                 {
  1193.                     BeginSetServerStatusOption(gEp.ep, kSetIdleStr);
  1194.                     ClrStatusBusyFlag(gFlags);
  1195.                 }
  1196.             }
  1197.             ClrCheckOptFlag(gFlags);
  1198.         }
  1199.                     
  1200.  
  1201.     }
  1202.  
  1203. }
  1204.  
  1205. /* Do the right thing for an event.  Determine what kind of event it is, and
  1206. ** call the appropriate routines. */
  1207.  
  1208. void    DoEvent(EventRecord *event)
  1209. {
  1210.     Point    pt;
  1211.     char    key;
  1212.  
  1213.     switch(event->what) 
  1214.     {
  1215.  
  1216.         case nullEvent:
  1217.         case mouseDown:
  1218.         case activateEvt:
  1219.         case updateEvt:
  1220.         case kHighLevelEvent:
  1221.             break;
  1222.  
  1223.         case autoKey:
  1224.         case keyDown:
  1225.             key = event->message & charCodeMask;
  1226.             switch (key)
  1227.             {
  1228.                 case 'q':
  1229.                 case 'Q':
  1230.                     if (event->modifiers & cmdKey)
  1231.                     gDone = true;
  1232.                     break;
  1233.             }
  1234.             break;
  1235.  
  1236.         case osEvt:
  1237.             switch ((event->message >> 24) & 0xFF) 
  1238.             {
  1239.                     /* Must logical and with 0xFF to get only low byte. */
  1240.                     /* High byte of message. */
  1241.  
  1242.                 case mouseMovedMessage:
  1243.                     break;
  1244.  
  1245.                 case suspendResumeMessage:
  1246.                         /* Suspend/resume is also an activate/deactivate. */
  1247.                     if ((event->message) & resumeFlag)
  1248.                         ClrInBackGndFlag(gFlags);    // process has come to the foreground
  1249.                     else
  1250.                         SetInBackGndFlag(gFlags);    // process has gone into background
  1251.                     break;
  1252.             }
  1253.             break;
  1254.  
  1255.         case diskEvt:
  1256.             if (HiWord(event->message) != noErr) 
  1257.             {
  1258.                 SetPt(&pt, kDILeft, kDITop);
  1259.                 DIBadMount(pt, event->message);
  1260.             }        /* It is not a bad idea to at least call DIBadMount in response to */
  1261.             break;    /* a diskEvt, so that the user can format a floppy. */
  1262.     }
  1263.  
  1264. }
  1265.  
  1266.  
  1267. /*******************************************************************************
  1268.     DoOTUnbind
  1269.     Call to make the OTUnbind request and check for an error result.
  1270.     Once this call is made, we don't want to protect against the OTUnbind
  1271.     from being called a second time.  If the OTUnbind call is made a second time
  1272.     before the T_UNBINDCOMPLETE event has occurred, then the call results in an
  1273.     StateChangeErr
  1274.     
  1275.     // RRK 3/9/99 add new code to protect against multiple unbind calls
  1276.     
  1277. ********************************************************************************/
  1278.  
  1279. OSStatus DoOTUnbind(MyEndpointRef *theEp)
  1280. {
  1281.     OSStatus    err = kOTNoError;
  1282.     Boolean        isSync;
  1283.     
  1284. //    OTDebugStr("Entered DoOTUnbind");
  1285.     
  1286.     if (TstEPBoundFlag(theEp->flags) && !TstUnbindPendFlag(theEp->flags))
  1287.     {
  1288.             // check whether the ep is asynch and set a flag to indicate we are waiting for the
  1289.             // unbind to complete.  We have to set the flag before we issue the call as
  1290.             // the T_UNBINDCOMPLETE call could occur before we could set the flag is done
  1291.             // after the OTUnbind call
  1292.         isSync = OTIsSynchronous(theEp->ep);
  1293.         
  1294.         if (isSync == false)
  1295.         {
  1296.             SetUnbindPendFlag(theEp->flags);
  1297.         }
  1298.             
  1299.         OTDebugStr("About to call OTUnbind");
  1300.         err = OTUnbind(theEp->ep);
  1301.         if (err != kOTNoError)
  1302.         {
  1303.             DoValueBreak(err, "Error calling OTUnbind #");
  1304.             SetForceCloseFlag(theEp->flags);
  1305.                 // on err clear the UnbindPendFlag
  1306.             ClrUnbindPendFlag(theEp->flags);
  1307.         }
  1308.         else
  1309.         {
  1310.             if (isSync == true)
  1311.             {
  1312.                 ClrEPBusyFlag(theEp->flags);
  1313.                 ClrEPBoundFlag(theEp->flags);
  1314.             }
  1315.         }
  1316.     }
  1317.     return err;
  1318. }
  1319.  
  1320. /*******************************************************************************
  1321. ** DoBind
  1322. **    Implements the option to set the qlen field and to bing with an nbpName
  1323. **    by setting the nbpName field with a pointer to an entity name.
  1324. **     If nbpName is not nil, you must also set the nbpNameLen to the size of the
  1325. **    nbpName field. Note, nbpName is not a pascal nor a C string.  
  1326. ********************************************************************************/
  1327.  
  1328. OSStatus DoBind(EndpointRef ep, UInt8 socket, UInt8 type, OTQLen qlen, 
  1329.                     char *nbpName, UInt32 nbpNameLen)
  1330. {
  1331.     TBind            req, ret;
  1332.     OSStatus         err = kOTNoError;
  1333.     DDPNBPAddress    addr;
  1334.     
  1335.  
  1336.     // init the DDPAddress variable    
  1337.     if (nbpName == nil)        // are we registering with no nbp name
  1338.     {
  1339.         addr.fAddressType = AF_ATALK_DDP;        // set the address type
  1340.         req.addr.len    = kDDPAddressLength;
  1341.     }
  1342.     else
  1343.     {
  1344.         addr.fAddressType = AF_ATALK_DDPNBP;    // registering with an nbp name
  1345.                                                 // copy the name to the name buffer
  1346.         BlockMove(nbpName, &addr.fNBPNameBuffer, nbpNameLen);
  1347.                                                 // set the request length to include the name len
  1348.         req.addr.len    = kDDPAddressLength + nbpNameLen;
  1349.     }
  1350.     
  1351.     addr.fNetwork = 0;
  1352.     addr.fNodeID = 0;
  1353.     addr.fSocket = socket;
  1354.     addr.fDDPType = type;
  1355.     
  1356.     // set up the request
  1357.     req.addr.buf    = (UInt8*)&addr;
  1358.     req.qlen        = qlen;
  1359.     
  1360.     // set up the response
  1361.     ret.addr.buf    = (UInt8*)&addr;
  1362.     ret.addr.maxlen    = sizeof(addr);
  1363.  
  1364.     fprintf(stderr, "Doing Bind\n");
  1365.  
  1366.     //
  1367.     // Try to bind
  1368.     // 
  1369.     err = OTBind(ep, &req, &ret);
  1370.  
  1371.     if ( err != kOTNoError )
  1372.     {
  1373.         fprintf(stderr, "PAPSample: DoBind returns error %ld\n", err);
  1374.         return err;
  1375.     }
  1376.  
  1377.     fprintf(stderr, "Bound address = ");
  1378.     ShowDDPAddress((DDPAddress*)&addr);
  1379.     fprintf(stderr, "\n");
  1380.     fprintf(stderr, "Bound queue len is %ld\n", ret.qlen);
  1381.  
  1382.     fprintf(stderr, "After Bind, ");
  1383.     ShowEndpointState(ep, "");
  1384.  
  1385.     return err;
  1386. }
  1387.  
  1388. /*******************************************************************************
  1389. ** StartAbortiveDisconnect        RRK 3/9/99 addition
  1390. **    starts an abortive disconnect of the endpoint by first forcing a flush of the
  1391.     cache, which results in a kStreamIoctlEvent handler event
  1392. ********************************************************************************/
  1393.  
  1394. OSStatus StartAbortiveDisconnect(MyEndpointRef *myEp)
  1395. {
  1396.     OSStatus    err = kOTNoError;
  1397.     
  1398.     err = OTIoctl(myEp->ep, I_FLUSH, (void*) FLUSHRW);
  1399.     if (err) 
  1400.         DoOTUnbind(myEp->ep);
  1401.     
  1402.     return err;
  1403. }
  1404.  
  1405. /*******************************************************************************
  1406. ** ActivatePAPEndpoint
  1407. ** 
  1408. ********************************************************************************/
  1409.  
  1410. OSStatus ActivatePAPEndpoint(MyEndpointRef *myEp)
  1411. {
  1412.     OSStatus    err = kOTNoError;
  1413.     OTResult    result;
  1414.     
  1415.     //
  1416.     // Create a PAP endpoint
  1417.     // Open listener, using the tilisten module to make 
  1418.     // listen/accept/disconnect processing much simpler.
  1419.     //
  1420.     myEp->ep = OTOpenEndpoint(OTCreateConfiguration("tilisten, pap"), 0, NULL, &err);
  1421.  
  1422.     if ( myEp->ep == NULL || err != kOTNoError )
  1423.     {
  1424.         myEp->ep = NULL;
  1425.         
  1426.         if (err == kOTNoError)
  1427.             err = memFullErr;
  1428.             
  1429.         fprintf(stderr,"ERROR: OpenEndpoint(\"pap\") failed with %ld\n", err);
  1430.     }
  1431.     else
  1432.     {
  1433.         SetEPActiveFlag(myEp->flags);
  1434.     }
  1435.  
  1436. #if HANDOFF_EP
  1437. #else
  1438.     if (err == kOTNoError)
  1439.     {
  1440.  
  1441.             // turn on the EOM option
  1442.         err = DoNegotiateEOMOption(myEp->ep, true);
  1443.         if (err != kOTNoError)
  1444.         {
  1445.             ClrEOMOnFlag(myEp->flags);
  1446.             fprintf(stderr, "\n\nError setting EOM option!\n");
  1447.         }
  1448.         else
  1449.         {
  1450.             SetEOMOnFlag(myEp->flags);
  1451.         }
  1452.     }
  1453. #endif
  1454.     
  1455.     if (err == kOTNoError)
  1456.     {
  1457.         //
  1458.         // Install notifier we're going to use for testing - we do this before
  1459.         //         binding - at this point, we're still synchronous
  1460.         //
  1461.         err = OTInstallNotifier(myEp->ep, EventHandler, (void*)myEp);
  1462.         if ( err != kOTNoError )
  1463.         {
  1464.             fprintf(stderr, "ERROR: InstallNotifier() failed with %ld\n for server endpoint", err);
  1465.         }
  1466.     }
  1467.         
  1468.     if (err == kOTNoError)
  1469.     {
  1470.  
  1471.         /*-------------------------------------------------------------------------
  1472.         Bind the endpoint endpoint using NBP
  1473.         ------------------------------------------------------------------------- */
  1474.  
  1475. #if HANDOFF_EP
  1476.         err = DoBind(myEp->ep, kDynamicSocket, kATPType, kMaxHandoffEPs, (char*)gServerNBPNameStr, clen((char*)gServerNBPNameStr));
  1477. #else
  1478.         err = DoBind(myEp->ep, kDynamicSocket, kATPType, 1, (char*)gServerNBPNameStr, clen((char*)gServerNBPNameStr));
  1479. #endif
  1480.  
  1481.         if ( err != kOTNoError )
  1482.         {
  1483.             fprintf(stderr, "PAPSample: bind of server endpoint failed.\n");
  1484.         }
  1485.         else
  1486.         {
  1487.             SetEPBoundFlag(myEp->flags);
  1488.         }
  1489.     }
  1490.  
  1491.     /*-------------------------------------------------------------------------
  1492.     Enable self send
  1493.         have to do this before we set the endpoint into async mode.
  1494.     ------------------------------------------------------------------------- */
  1495.     if (err == kOTNoError)
  1496.     {
  1497.         err = DoNegotiateSelfSendOption(myEp->ep, 1);
  1498.         
  1499.         if (err < kOTNoError)
  1500.         {
  1501.             fprintf(stderr, "error negotiating selfsend on main endpoint\n");
  1502.             err = kOTNoError;    // don't let this stop the app.
  1503.         }
  1504.         else if (err > kOTNoError)
  1505.         {
  1506.             fprintf(stderr, "selfsend previously enable\n");
  1507.             err = kOTNoError;    // don't let this stop the app.
  1508.         }
  1509.         else
  1510.         {
  1511.             fprintf(stderr, "selfsend enabled\n");
  1512.         }
  1513.     }
  1514.     
  1515.         // lastly, set endpoint into async modez
  1516.     if (err == kOTNoError)
  1517.         OTSetAsynchronous(myEp->ep);
  1518.     
  1519.  
  1520.     /*-------------------------------------------------------------------------
  1521.     Set the server status string
  1522.     ------------------------------------------------------------------------- */
  1523.     if (err == kOTNoError)
  1524.         BeginSetServerStatusOption(myEp->ep, kSetIdleStr);
  1525.     
  1526.     
  1527.     
  1528.     return err;
  1529. }
  1530.  
  1531. #if HANDOFF_EP
  1532. /*******************************************************************************
  1533. ** ActivateHandoffEndpoint function - Open prepare a handoff endpoint for the
  1534.    PAP server
  1535. ********************************************************************************/
  1536.  
  1537. OSStatus ActivateHandoffEndpoint(MyEndpointRef *myEp)
  1538. {
  1539.     OSStatus    err;
  1540.     
  1541.     myEp->ep = OTOpenEndpoint(OTCreateConfiguration(kPAPName), (OTOpenFlags)NULL, NULL, &err);
  1542.     if (err == kOTNoError)
  1543.     {
  1544.         SetEPActiveFlag(myEp->flags);
  1545.             // turn on the EOM option
  1546.         err = DoNegotiateEOMOption(myEp->ep, true);
  1547.         if (err != kOTNoError)
  1548.         {
  1549.             ClrEOMOnFlag(myEp->flags);
  1550.             fprintf(stderr, "\nError setting EOM option %d\n", err);
  1551.         }
  1552.         else
  1553.         {
  1554.             SetEOMOnFlag(myEp->flags);
  1555.         }
  1556.     }
  1557.  
  1558.     if (err == kOTNoError)
  1559.     {
  1560.         err = OTInstallNotifier(myEp->ep, EventHandler, (void*)myEp);
  1561.         if ( err != kOTNoError )
  1562.         {
  1563.             fprintf(stderr, "ERROR: InstallNotifier() failed with %ld\n for handoff endpoint &d\n", err);
  1564.         }
  1565.         else
  1566.             OTSetAsynchronous(myEp->ep);
  1567.  
  1568.     }
  1569.  
  1570.     return err;        
  1571. }
  1572. #endif
  1573.  
  1574. /*******************************************************************************
  1575. ** InitMyEndpointRef function - zero out the MyEndpointRef structure
  1576. **     Course we could use the memset function here.
  1577. ********************************************************************************/
  1578.  
  1579. OSStatus InitMyEndpointRef(MyEndpointRef *myEp)
  1580. {
  1581.     myEp->ep = nil;
  1582.     myEp->flags = 0;
  1583.     myEp->usedQ = OTAllocMem(sizeof(OTLIFO));
  1584.     if (myEp->usedQ == nil)
  1585.         return memFullErr;
  1586.     
  1587.     myEp->usedQ->fHead = nil;        // no packets with this endpoint.
  1588.     
  1589.     return kOTNoError;
  1590. }
  1591.  
  1592.  
  1593. OSStatus InitPAPBuffers(void)
  1594. {
  1595.     PacketPtr        packetPtr;
  1596.     OSStatus        err = kOTNoError;
  1597.     short            i;
  1598.     
  1599.         // allocate memory for the freeQ
  1600.     gFreeQ = OTAllocMem(sizeof(OTLIFO));
  1601.     if (gFreeQ == nil)
  1602.         return memFullErr;
  1603.         
  1604.     /* set up the free queue */
  1605.     gFreeQ->fHead = nil;
  1606.     
  1607.         // allocate a temp buffer to be used when packet data overlaps.
  1608.     gTempPackPtr = OTAllocMem(sizeof(PacketBuffer) + kPAPDataSize);    
  1609.     if (gTempPackPtr == nil)
  1610.         err = memFullErr;
  1611.  
  1612.     /* enqueue the packet buffer records to the free queue */
  1613.     for (i=0; (i<kNumBuffers) && (err == kOTNoError); i++)
  1614.     {
  1615.             // before calling OTAllocMem, we must have already have called
  1616.             // InitOpenTransport
  1617.             
  1618.         packetPtr = OTAllocMem(sizeof(PacketBuffer));
  1619.         if (packetPtr != nil)
  1620.         {
  1621.             packetPtr->flags = 0;
  1622.             packetPtr->fLink.fNext = nil;
  1623.             OTLIFOEnqueue(gFreeQ, &(packetPtr->fLink));    // first field is fLink field
  1624.             
  1625.         }
  1626.         else
  1627.             err = memFullErr;
  1628.     }
  1629.     
  1630.     if (err == kOTNoError)
  1631.     {
  1632.         /* show that the buffers have been init'd */
  1633.         SetBufsInitdFlag(gFlags);
  1634.  
  1635.         /* note that we don't need to worry about holding memory in the
  1636.             presence of VM.  The notifier routine will be called at
  1637.             deferred task time when it is safe to page memory
  1638.          */
  1639.         
  1640.     }
  1641.     else
  1642.     {
  1643.         fprintf(stderr, "\n\nError allocating receive buffers!\n");
  1644.         fprintf(stderr, "\nBye Bye.\n");
  1645.     }
  1646.         
  1647.     return(err);
  1648.  
  1649. }
  1650.  
  1651.     
  1652.  
  1653. /*******************************************************************************
  1654. ** Initialize OpenTransport and call DoTest function
  1655. ********************************************************************************/
  1656. OSStatus InitPAPServerStuff(void)
  1657. {
  1658.     OSStatus    err = kOTNoError;
  1659.     UInt32        growAmt, selection;
  1660.     UInt32        i;
  1661.     char        mystr[255];    
  1662.                 
  1663.         // register ourselves with OT
  1664.     OTRegisterAsClient((OTClientName) "PAPServerSample", nil);
  1665.  
  1666.         // ask whether to alter current options
  1667.     fprintf(stdout, "\nDo you want to change the current options?");
  1668.     fprintf(stdout, "\n  Options which can be changed:");
  1669.     fprintf(stdout, "\n                    1. SetMemoryLimits");
  1670.     fprintf(stdout, "\n                    2. Dump packets");
  1671.     fprintf(stdout, "\n    Enter - n to use default settings");
  1672.     fprintf(stdout, "\n    Enter - y to alter above settings");
  1673.  
  1674.     selection = GetYesNoOption();
  1675.     if (selection == kQuitTest)
  1676.         err = -1;
  1677.     else if (selection == kAcceptOption)
  1678.     {
  1679.             // ask whether to use the set memory limits option or not
  1680.         fprintf(stdout, "\nDo you want to set memory limits?");
  1681.         selection = GetYesNoOption();
  1682.         
  1683.         if (selection == kQuitTest)
  1684.             err = -1;
  1685.         else if (selection == kAcceptOption)
  1686.         {
  1687.             fprintf(stderr, "How much memory to grow heap ?\n");
  1688.             fprintf(stdout, "\n  Enter - n to use default setting");
  1689.             fprintf(stdout, "\n  Enter - y to set heap growth");
  1690.             if (gets(mystr) != 0)
  1691.             {
  1692.                 stringtonum(mystr, (long*)&growAmt);
  1693.                 OTSetMemoryLimits(growAmt, 0);
  1694.                 
  1695.             }
  1696.         }
  1697.         
  1698.         if (err == kOTNoError)
  1699.         {
  1700.                 // ask whether to use the set memory limits option or not
  1701.             fprintf(stdout, "\nDo you want to just dump packets?");
  1702.             fprintf(stdout, "\n  Enter - n to save packets to default file");
  1703.             fprintf(stdout, "\n  Enter - y to dump packets");
  1704.             selection = GetYesNoOption();
  1705.             if (selection == kQuitTest)
  1706.                 err = -1;
  1707.             else if (selection == kAcceptOption)
  1708.             {
  1709.                 SetdumpAllPktsFlag(gFlags);
  1710.             }
  1711.         }
  1712.     }
  1713.  
  1714.     if (err == kOTNoError)
  1715.     {
  1716.  
  1717.             // load in the various strings
  1718.         GetIndString((unsigned char*)&gIdleStr, kServerStrID, kIdleStrID);
  1719.         GetIndString((unsigned char*)&gBusyStr, kServerStrID, kBusyStrID);
  1720.         GetIndString((unsigned char*)&gServerNBPNameStr, kServerStrID, kServerNBPStrID);
  1721.             // covert each string to c
  1722.         p2c(gIdleStr);
  1723.         p2c(gBusyStr);
  1724.         p2c(gServerNBPNameStr);
  1725.     
  1726.         // initialize the endpoint ref
  1727.         err = InitMyEndpointRef(&gEp);
  1728.     }
  1729.     
  1730.     if (err == kOTNoError)
  1731.     {
  1732. #if HANDOFF_EP
  1733.         for (i = 0; (i < kMaxHandoffEPs) && (err == kOTNoError) ; i++)
  1734.             err = InitMyEndpointRef(&gHandoffEp[i]);
  1735. #endif
  1736.     }
  1737.  
  1738.     if (err == kOTNoError)
  1739.     {
  1740.         //
  1741.         // Initialize the buffers
  1742.         //
  1743.         err = InitPAPBuffers();
  1744.     }
  1745.             
  1746.  
  1747.     if (err == kOTNoError)
  1748.     {
  1749.         //
  1750.         //  Init the server endpoint
  1751.         //
  1752.         err = ActivatePAPEndpoint(&gEp);
  1753.     }
  1754.  
  1755. #if HANDOFF_EP
  1756.     if (err == kOTNoError)
  1757.     {
  1758.         //
  1759.         //  Init the handoff endpoint
  1760.         //
  1761.         for (i = 0; (i < kMaxHandoffEPs) && (err == kOTNoError); i++)
  1762.             err = ActivateHandoffEndpoint(&gHandoffEp[i]);        // RRK 3/10/99 call ActivateHandoffEndpoint
  1763.  
  1764.         if (err != kOTNoError)
  1765.         {
  1766.             fprintf(stderr, "\n\nError opening the handoff endpoint!\n");
  1767.             fprintf(stderr, "\nBye Bye.\n");
  1768.         }
  1769.     }
  1770.  
  1771. #endif        // HANDOFF_EP    
  1772.         
  1773.     return err;
  1774.     
  1775. }
  1776.  
  1777.  
  1778. /*******************************************************************************
  1779. ** ReleasePAPMemory
  1780. ********************************************************************************/
  1781.  
  1782. void ReleasePAPMemory(void)
  1783. {
  1784.     PacketPtr    packetPtr;
  1785.     OTLIFO        *otLIFOPtr;
  1786.     short        i;
  1787.     
  1788.     if (gTempPackPtr)
  1789.         OTFreeMem(gTempPackPtr);
  1790.         
  1791.         // first release the freeQ memory
  1792.     otLIFOPtr = gFreeQ;
  1793.     packetPtr = (PacketPtr)OTLIFODequeue(otLIFOPtr);
  1794.     
  1795.     while (packetPtr != nil)    // while the queue is not empty
  1796.     {
  1797.                 // free the packetbuffer
  1798.         OTFreeMem(packetPtr);
  1799.         packetPtr = (PacketPtr)OTLIFODequeue(otLIFOPtr);            
  1800.     }
  1801.  
  1802. #if HANDOFF_EP
  1803.     for (i = 0; i < kMaxHandoffEPs; i++)        // 
  1804.     {
  1805.         otLIFOPtr = gHandoffEp[i].usedQ;
  1806. #else
  1807.         otLIFOPtr = gEp.usedQ;
  1808. #endif
  1809.         if (otLIFOPtr->fHead)
  1810.             fprintf(stderr, "Am releasing buffer from the used queue.\n\n");
  1811.         
  1812.         packetPtr = (PacketPtr)OTLIFODequeue(otLIFOPtr);
  1813.         
  1814.         while (packetPtr != nil)    // while the queue is not empty
  1815.         {
  1816.                     // free the packetbuffer
  1817.             OTFreeMem(packetPtr);
  1818.             packetPtr = (PacketPtr)OTLIFODequeue(otLIFOPtr);            
  1819.         }
  1820.     
  1821. #if HANDOFF_EP
  1822.     }
  1823. #endif
  1824.     
  1825.     OTFreeMem(gFreeQ);
  1826.     
  1827. }
  1828.  
  1829. /*******************************************************************************
  1830. ** Close endpoints, and OpenTransport 
  1831. ********************************************************************************/
  1832.  
  1833. void ClosePAPServerStuff(void)
  1834. {
  1835.  
  1836.     short i;
  1837.  
  1838.     if (gEp.ep)
  1839.         OTSetSynchronous(gEp.ep);
  1840.  
  1841.     // note that we don't check whether the endpoint is still connected.  Since
  1842.     // we are leving anyway, let the UnBind call clear things up.  If we did do a
  1843.     // disconnect here, we would meed to also implement a timer mechanism. so that
  1844.     // we didn't get hung awaiting a DisconnectComplete event that might not come.
  1845.     
  1846. #if HANDOFF_EP
  1847.     for (i = 0; i < kMaxHandoffEPs; i++)
  1848.     {
  1849.  
  1850.         if (gHandoffEp[i].ep)
  1851.             OTSetSynchronous(gHandoffEp[i].ep);
  1852.         
  1853.         if (TstEPBoundFlag(gHandoffEp[i].flags))    // is the handoff endpoint bound
  1854.             DoOTUnbind(gHandoffEp[i].ep);            // unbind the endpoint
  1855.                                                     // RRK 3/9/99 change to protect against multiple unbinds
  1856.         
  1857.         if (gHandoffEp[i].usedQ != nil)            // free allocated memory with usedQ.
  1858.             OTFreeMem(gHandoffEp[i].usedQ);
  1859.             
  1860.         if (TstEPActiveFlag(gHandoffEp[i].flags))    // is the handoff endpoint open
  1861.             OTCloseProvider(gHandoffEp[i].ep);        // close the endpoint
  1862.             
  1863.     }
  1864.  
  1865. #endif
  1866.             
  1867.     if (TstEPBoundFlag(gEp.flags))            // is the server endpoint bound
  1868.         DoOTUnbind(gEp.ep);                    // unbind the endpoint
  1869.                                             // RRK 3/9/99 change to protect against multiple unbinds
  1870.         
  1871.     if (gEp.usedQ != nil)                    // free allocated memory with usedQ.
  1872.         OTFreeMem(gEp.usedQ);
  1873.         
  1874.     if (TstEPActiveFlag(gEp.flags))            // is the server endpoint open
  1875.         OTCloseProvider(gEp.ep);            // close the endpoint
  1876.         
  1877.     // ReleasePAPMemory();                        // release memory before OT goes away
  1878.                                             // not really necessary since we are just going to 
  1879.                                             // exit after this.
  1880.  
  1881.     if (gFreeQ != nil)
  1882.         OTFreeMem(gFreeQ);
  1883.     
  1884.     if (TstOTActiveFlag(gFlags))            // is OpenTransport active
  1885.         CloseOpenTransport();                // shutdown OT services
  1886.     
  1887. }
  1888.  
  1889. //
  1890. //    NetInit:
  1891. //
  1892. //    This routine does various networking related startup tasks:
  1893. //
  1894. //    (1) it does InitOpenTransport
  1895. //    (2) it records the OT version for us.
  1896. //
  1897. //  result - true - OpenTransport init'd and the correct version is present
  1898. //             false - problem opening OT or OT version not correct
  1899. //
  1900. static Boolean NetInit()
  1901. {
  1902.     OSStatus err;
  1903.  
  1904.     err = Gestalt(gOTVersionSelector, (long*) &gOTVersion);
  1905.     if (err || (gOTVersion < kOTVersion111))
  1906.     {
  1907.         fprintf(stderr, "Please install Open Transport 1.1.1 or later");
  1908.         return false;
  1909.     }
  1910.     
  1911.     err = InitOpenTransport();
  1912.     if (err)
  1913.     {
  1914.         fprintf(stderr, "NetInit: InitOpenTransport error %d", err);
  1915.         return false;
  1916.     }
  1917.     return true;
  1918. }
  1919.  
  1920.  
  1921. /*******************************************************************************
  1922. ** main function
  1923. ********************************************************************************/
  1924.  
  1925. main(void) 
  1926. {
  1927.     OSStatus    osstatus;
  1928.     
  1929. //    InitGraf(&qd.thePort);                    // initialize quickdraw so we can use regions
  1930.  
  1931.     fprintf(stderr, "PAPServerSample showing implementation of PAP server.\n\n");
  1932.  
  1933.     // init the flags variable
  1934.     gFlags = 0;
  1935.  
  1936.  
  1937.     if (NetInit() == false)
  1938.         return 0;
  1939.     
  1940.     //
  1941.     // Initialize the OT and the global Endpoints
  1942.     //
  1943.     osstatus = InitPAPServerStuff();
  1944.     
  1945.     if (osstatus == kOTNoError)
  1946.     {
  1947.     
  1948.  
  1949.         //
  1950.         // Run the PAPServer code
  1951.         //
  1952.         DoServer();
  1953.         //
  1954.     }
  1955.     
  1956.     //
  1957.     // Close things down
  1958.     //
  1959.     ClosePAPServerStuff();
  1960.     
  1961.     CheckFileToClose();
  1962.     
  1963.     fprintf(stderr, "\n\nDone\n");
  1964.         
  1965.     return 0;
  1966. }
  1967.  
  1968. void DoValueBreak(long value, const char* message)
  1969. {
  1970.     static short    sDoErrorBreak = 0;
  1971.  
  1972.     {
  1973.         Str255    s,
  1974.                 n = "\p";
  1975.  
  1976.         s[0] = strlen(message);
  1977.         BlockMoveData(message,&s[1],s[0]);
  1978.         if (value < 0)
  1979.         {
  1980.             s[0] += 1;
  1981.             s[s[0]] = '-';
  1982.             value = -value;
  1983.         }
  1984.         while (value)
  1985.         {
  1986.             if (n[0])
  1987.                 BlockMoveData(&n[1],&n[2],n[0]);
  1988.             n[0]++;
  1989.             n[1] = 48 + (value % 10);
  1990.             value /= 10;
  1991.         }
  1992.         BlockMoveData(&n[1],&s[s[0]+1],n[0]);
  1993.         s[0] += n[0];
  1994.  
  1995.         sDoErrorBreak++;
  1996.         {
  1997.             short    cnt = sDoErrorBreak;
  1998.  
  1999.             s[0]++;
  2000.             s[s[0]] = ',';
  2001.             s[0]++;
  2002.             s[s[0]] = ' ';
  2003.             n[0] = 0;
  2004.             while (cnt)
  2005.             {
  2006.                 if (n[0])
  2007.                     BlockMoveData(&n[1],&n[2],n[0]);
  2008.                 n[0]++;
  2009.                 n[1] = 48 + (cnt % 10);
  2010.                 cnt /= 10;
  2011.             }
  2012.             BlockMoveData(&n[1],&s[s[0]+1],n[0]);
  2013.             s[0] += n[0];
  2014.         }
  2015.         OTDebugStr((const char *)s);
  2016.     }
  2017. }
  2018.  
  2019.  
  2020. OSStatus BeginSetServerStatusOption(EndpointRef ep, UInt16 whichStr)
  2021. {
  2022.     OSStatus    err;
  2023.     unsigned char    *in = "\p._in";
  2024.     
  2025.     if (whichStr == kSetIdleStr)
  2026.     {
  2027.         err = DoSetServerStatusOption(ep, (char*)&gIdleStr);
  2028.     }
  2029.     else
  2030.     {
  2031.         err = DoSetServerStatusOption(ep, (char*)&gBusyStr);
  2032.     }
  2033.     
  2034.     if (err != kOTNoError)
  2035.     {
  2036.         fprintf(stderr, "ServerStatus option call failed\n");
  2037.         fprintf(stderr, "however, this will not keep the server from running\n");
  2038.         err = kOTNoError;
  2039.     }
  2040.     
  2041.     return err;
  2042. }
  2043.  
  2044.  
  2045. UInt32 GetYesNoOption(void)
  2046. {
  2047.     UInt32    result;
  2048.     char    selection[32];
  2049.     Boolean    done;
  2050.     
  2051.     fprintf(stdout, "\n    Enter Q - To quit");
  2052.     fprintf(stdout, "\nYour selection -> ");
  2053.     fflush(stdout);
  2054.     done = false;
  2055.  
  2056.     do
  2057.     {
  2058.         if (gets(selection) != 0)
  2059.         {
  2060.             switch (selection[0])
  2061.             {
  2062.                 case 'y':
  2063.                 case 'Y':
  2064.                     result = kAcceptOption;
  2065.                     done = true;
  2066.                     break;
  2067.                 
  2068.                 case 'n':
  2069.                 case 'N':
  2070.                     result = kDeclineOption;
  2071.                     done = true;
  2072.                     break;
  2073.  
  2074.                 case 'q':
  2075.                 case 'Q':
  2076.                     result = kQuitTest;
  2077.                     done = true;
  2078.                     break;
  2079.                     
  2080.                 default:
  2081.                     fprintf(stdout, "\nInvalid entry - %c, try again -> ", selection);
  2082.                     fflush(stdout);
  2083.                     break;
  2084.  
  2085.             }
  2086.         }
  2087.     } while (!done);
  2088.     
  2089.     fflush (stdout);
  2090.     return result;
  2091. }
  2092.  
  2093.  
  2094. #if HANDOFF_EP
  2095. /*
  2096.     Iterate through the handoff endpoints and find one that doesn't have the busy flag
  2097.     set - return the pointer else return null
  2098. */
  2099. MyEndpointRef*    FindFreeHandoffEp(void)
  2100. {
  2101.     short    i;
  2102.     
  2103.     for (i = 0; i < kMaxHandoffEPs; i++)
  2104.     {        // RRK 3/9/99 change to protect against the use of a handoff endpoint that is
  2105.             // not active, will be forced to close, or is busy
  2106.             // don't allow use of a handoff endpoint if the endpoint is
  2107.             // busy, or if it will be closed, or if it not active
  2108.         if ((TstEPBusyFlag(gHandoffEp[i].flags) == false) && 
  2109.             (TstEPActiveFlag(gHandoffEp[i].flags) == true) &&
  2110.             (TstOpenPendFlag(gHandoffEp[i].flags) == false) &&
  2111.             (TstForceCloseFlag(gHandoffEp[i].flags) == false))
  2112.             return &gHandoffEp[i];
  2113.     }
  2114.     
  2115.     return nil;
  2116. }
  2117. #endif
  2118.  
  2119. Boolean EndpointsAllBusy(void)
  2120. {
  2121.     Boolean        result = true;    
  2122. #if HANDOFF_EP
  2123.     short        i;
  2124.     
  2125.     for (i = 0; (i < kMaxHandoffEPs) && (result == true); i++)
  2126.     {
  2127.         if (TstEPBusyFlag(gHandoffEp[i].flags) == false)
  2128.             result = false;    // any endpoint not busy means that not all eps are busy
  2129.     }
  2130.  
  2131. #else
  2132.     result = TstEPBusyFlag(gEp.flags);
  2133.         
  2134. #endif
  2135.     
  2136.     return result;
  2137. }